#ifndef CANREADER_H
#define CANREADER_H
#include <string>
#include <memory>
#include <set>
#include <linux/can.h>
#include <optional>
#include <functional>
#include <any>
#include "Logger.h"
#include "ringbuffer.hpp"
#include "SpinLock.hpp"


namespace canpp {
    using std::string;
    using std::set;
    using std::shared_ptr;
    using std::optional;
    using std::nullopt;
    using std::function;
    using std::any;
    using bq::log;
    using jnk0le::Ringbuffer;


    class CanReader {
    public:
        CanReader() = delete;

        ~CanReader();

        explicit CanReader(string &&canInterface, optional<string> &&id = nullopt,
                           optional<set<uint16_t> > &&canMasks = nullopt);

        explicit CanReader(string &canInterface, const optional<string> &id = nullopt,
                           const optional<set<uint16_t> > &canMasks = nullopt);

        can_frame peekMessage();

        void pushMessage(const can_frame &&frame);

        void registerCallback(const std::function<void(const can_frame &&)> &func);

        void registerCallback(std::function<void(const can_frame &&)> &&func);

        [[nodiscard]] string get_id() const {
            return id;
        }

        set<uint16_t> &get_masks() {
            return std::ref(masks);
        }

    private:
        log logger;
        string interface;
        string id;
        set<uint16_t> masks;

        Ringbuffer<can_frame> messages{};
        SpinLock callback_lock;
        function<void(const can_frame &&)> callback{
            [](const can_frame &&) -> void {
            }
        };
    };
} // canpp

#endif //CANREADER_H
